package cn.madis.ymcc.service.impl;

import cn.madis.ymcc.domain.Course;
import cn.madis.ymcc.domain.CourseMarket;
import cn.madis.ymcc.domain.KillActivity;
import cn.madis.ymcc.domain.KillCourse;
import cn.madis.ymcc.dto.ForecastOrder;
import cn.madis.ymcc.dto.KillParamDto;
import cn.madis.ymcc.mapper.KillCourseMapper;
import cn.madis.ymcc.service.IKillActivityService;
import cn.madis.ymcc.service.IKillCourseService;
import cn.madis.ymcc.util.AssertUtil;
import cn.madis.ymcc.util.CodeGenerateUtils;
import cn.madis.ymcc.utils.LoginSecurityContext;
import cn.madis.ymcc.vo.Course2OrderMax;
import cn.madis.ymcc.vo.Course2OrderMin;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Zt
 * @since 2022-08-23
 */
@Service
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {

    @Autowired
    private IKillActivityService killActivityService;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 课程添加秒杀
     * @param killCourse
     */
    @Override
    public void add(KillCourse killCourse) {
        //课程状态必须是上架的
        //一个活动只能有一个相同的课程只能
        Long activityId = killCourse.getActivityId();
        KillCourse killCourseTmp = selectActivityIdCourseId(activityId, killCourse.getCourseId());
        AssertUtil.isNull(killCourseTmp,"不能添加相同课程");
        //活动必须是待发布才能加入秒杀
        KillActivity killActivity = killActivityService.selectById(killCourse.getActivityId());
        boolean b = killActivity.getPublishStatus() == KillActivity.TOBERELEASED;
        AssertUtil.isTrue(b,"活动状态异常");
        //添加KillCourse数据.
        killCourse.setStartTime(killActivity.getBeginTime());
        killCourse.setEndTime(killActivity.getEndTime());
        killCourse.setCreateTime(new Date());
        killCourse.setPublishTime(killActivity.getPublishTime());
        killCourse.setKillLimit(1);
        killCourse.setTimeStr(killActivity.getTimeStr());
        insert(killCourse);
    }


    private KillCourse selectActivityIdCourseId(Long activityId, Long courseId) {
        EntityWrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id",courseId);
        wrapper.eq("activity_id",activityId);
        return selectOne(wrapper);
    }


    /**
     * 查询课程秒杀数据
     * @return
     */
    @Override
    public List<KillCourse> all() {
        //拿到所有key
        List<KillCourse> killCourses = new ArrayList<>();
        Set<Object> keys = redisTemplate.keys("activity*");
        keys.forEach(key->{
            List values = redisTemplate.opsForHash().values(key);
            killCourses.addAll(values);
        });
        //统一封装成集合返回
        return killCourses;
    }

    /**
     * 查询某个秒杀课程上架的
     * 从redis中查
     * @param killId
     * @param activityId
     * @return
     */
    @Override
    public KillCourse one(Long killId, Long activityId) {
        return (KillCourse) redisTemplate.opsForHash().get(
                "activity" + activityId,
                killId.toString()
        );
    }

    /**
     * 执行秒杀
     * @param killParamDto
     * @return
     */
    @Override
    public String kill(KillParamDto killParamDto) {
        KillCourse killCourse = one(killParamDto.getKillCourseId(),killParamDto.getActivityId());
        //1.业务判断不能重复秒杀
        //2.一个人只能秒杀一个商品一次

        //3.秒杀时间校验

        //4.找到课程 尝试减库存
        String semaphore = killParamDto.getActivityId() + ":" + killCourse.getCourseId();
        RSemaphore semaphoreTmp = redissonClient.getSemaphore(semaphore);
        boolean tryAcquire = semaphoreTmp.tryAcquire(1);
        //4.1扣减不成功 返回托底数据 没有秒杀到请下次再来
        AssertUtil.isTrue(tryAcquire,"下次再来");
        //4.2扣减成功生成预创订单存入redis
        Long loginId = LoginSecurityContext.getLoginJwtDtoContext().getId();
        ForecastOrder forecastOrder = new ForecastOrder();
        forecastOrder.setOrderNo(CodeGenerateUtils.generateOrderSn(loginId));
        forecastOrder.setCourseId(killCourse.getCourseId());
        forecastOrder.setCourseName(killCourse.getCourseName());
        forecastOrder.setCoursePic(killCourse.getCoursePic());
        forecastOrder.setTotalAmount(killCourse.getKillPrice());
        forecastOrder.setTotalCount(1);
        forecastOrder.setUserId(loginId);
        redisTemplate.opsForValue().set(forecastOrder.getOrderNo(),forecastOrder);

        //5.返回订单号

        return forecastOrder.getOrderNo();
    }

    /**
     * 秒杀订单详情页查询数据展示
     * @param orderNo
     * @return
     */
    @Override
    public Course2OrderMax oneByOrder(String orderNo) {
        AssertUtil.isNotNull(orderNo,"非法参数");
        Object obj = redisTemplate.opsForValue().get(orderNo);
        AssertUtil.isNotNull(obj,"查询不到");
        ForecastOrder forecastOrder = (ForecastOrder) obj;

        Course2OrderMin course2OrderMin = new Course2OrderMin();
        Course2OrderMax course2OrderMax = new Course2OrderMax();
        List<Course2OrderMin> courseInfos = new ArrayList<>();

        Course course = new Course();
        course.setName(forecastOrder.getCourseName());
        course.setId(forecastOrder.getCourseId());
        course.setPic(forecastOrder.getCoursePic());

        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setPrice(forecastOrder.getTotalAmount());


        courseInfos.add(new Course2OrderMin(course,courseMarket));
        course2OrderMax.setTotalAmount(courseMarket.getPrice());

        course2OrderMax.setCourseInfos(courseInfos);


        return course2OrderMax;
    }
}
